# importModels.R
# created 2012 July 19

# Import all of the models specified in a file into an environment.  
# Perhaps check the models for specification errors.  Then return an 
# environment containing all of the models.  [2012 08 04]

# endogVarNames is a character vector specifying the names of endogenous 
# variables in the model.  [2013 04 16]

importModels <- function(
  filename      = 'IV_models.R', 
  endogVarNames = 'HSgrad', 
  checkModels   = TRUE) {
  
  source('functions/formulaFunctions.R')
  
  models <- new.env()
  sys.source(filename, envir = models)
  modNames <- ls(envir = models)
  if (! all(grepl('\\d$', modNames))) {
    stop("Model names must end with a unique digit.")
  }
    
   
  # Check for errors in the models, e.g., variables in first stage that aren't
  # in second stage (other than the instruments).  [2012 07 26]
  RHSAttributeSet <- unlist(eapply(models, function (x) ! is.null(attributes(x)$rhs)))
  if (all(RHSAttributeSet) && checkModels) {
    for (modName in ls(env = models)) {
      mod <- get(modName, envir = models)
      checkIVModel(modName, mod, endogVarNames)  # will stop on error if there are problems
    }    
  }
  else if (checkModels) {
    warning("Some formulas lack an 'rhs' attribute, so no formulas are being checked for errors.")
  }
  else {
    warning("No models are being checked for errors.")
  }
  
  # Change the environment of the models, so that ivreg() looks for variables
  # in the global environment if it can't find them in the "data" data frame.
  # [2012 07 26]
  eapply(models, function (x) environment(x) <- .GlobalEnv)
  
  # Create a list of the models.  Lists can be indexed; environments 
  # can't be.  And indexing proves useful below.  [2012 07 26]
  modList <- as.list(models)

  # Add a "model number" attribute to each model.  This will be useful when 
  # I estimate all of the models for multiple variables at once, which I plan
  # to do with estimateIVModels().  [2012 07 26]
  modList <- addModNumAttribute(modList)
  
  # Put the list elements back into the environment.  [2012 07 31]
  models <- list2env(modList)  
  
  models
}


addModNumAttribute <- function (modList) {
  if (! class(modList) %in% 'list') {
    stop("modList must be a list.")
  }
  for (i in 1:length(modList)) {
    modName <- names(modList)[i]
    modNum  <- sub('.*(\\d)$', '\\1', modName)
    attributes(modList[[i]])$modNum <- modNum
  }
  modList
}
